﻿//  Copyright (c) 2009 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Collections;
using System.Globalization;

namespace DNA.Mvc.jQuery
{
    /// <summary>
    /// Represents support for jQuery ajax form in an application.
    /// </summary>
    public static class AjaxFormExtensions
    {
        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper)
        {
            return ajaxHelper.BeginAjaxForm("", "", null, null, null);
        }

        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper, string action)
        {
            return ajaxHelper.BeginAjaxForm(action, "", null, null, null);
        }

        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper, string action, IDictionary<string, object> htmlAttributes)
        {
            return ajaxHelper.BeginAjaxForm(action, "", null, null, htmlAttributes);
        }

        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper, string action, RouteValueDictionary routeData)
        {
            return ajaxHelper.BeginAjaxForm(action, "", null, routeData, null);
        }

        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper, string action, RouteValueDictionary routeData, IDictionary<string, object> htmlAttributes)
        {
            return ajaxHelper.BeginAjaxForm(action, "", null, routeData, htmlAttributes);
        }

        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper, string action, jQueryAjaxOptions options, RouteValueDictionary routeData, IDictionary<string, object> htmlAttributes)
        {
            return ajaxHelper.BeginAjaxForm(action, "", options, routeData, htmlAttributes);
        }

        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper, string action, string controllerName)
        {
            return ajaxHelper.BeginAjaxForm(action, controllerName, null, null, null);
        }

        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper, string action, string controllerName, jQueryAjaxOptions options, RouteValueDictionary routeData)
        {
            return ajaxHelper.BeginAjaxForm(action, controllerName, options, routeData, null);
        }

        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper, string action, string controllerName, RouteValueDictionary routeData)
        {
            return ajaxHelper.BeginAjaxForm(action, controllerName, null, routeData, null);
        }

        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper, string action, string controllerName, RouteValueDictionary routeData, IDictionary<string, object> htmlAttributes)
        {
            return ajaxHelper.BeginAjaxForm(action, controllerName, null, routeData, htmlAttributes);
        }

        public static MvcForm BeginAjaxForm(this AjaxHelper ajaxHelper, string action, string controllerName, jQueryAjaxOptions options, RouteValueDictionary routeData, IDictionary<string, object> htmlAttributes)
        {
            var opts = options == null ? new jQueryAjaxOptions() : options;
            string _action = string.IsNullOrEmpty(action) ? ajaxHelper.ViewContext.RouteData.Values["action"].ToString() : action;
            string _controllerName = string.IsNullOrEmpty(controllerName) ? ajaxHelper.ViewContext.RouteData.Values["controller"].ToString() : controllerName;

            if (string.IsNullOrEmpty(opts.Url))
            {
                UrlHelper urlHelper = new UrlHelper(ajaxHelper.ViewContext.RequestContext);
                if (routeData != null)
                    opts.Url = urlHelper.Action(_action, _controllerName, routeData);
                else
                    opts.Url = urlHelper.Action(_action, _controllerName);
            }

            return ajaxHelper.AjaxFormHelper(opts, htmlAttributes);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ajaxHelper"></param>
        /// <param name="options"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        private static MvcForm AjaxFormHelper(this AjaxHelper ajaxHelper, jQueryAjaxOptions options, IDictionary<string, object> htmlAttributes)
        {
            TagBuilder builder = new TagBuilder("form");
            builder.MergeAttributes<string, object>(htmlAttributes);
            builder.MergeAttribute("action", options.Url);
            builder.MergeAttribute("method", "post");

            if (!builder.Attributes.ContainsKey("id"))
                builder.GenerateId("form_" + Guid.NewGuid().ToString().Substring(0, 5));
            //if (ajaxHelper.ViewContext.ClientValidationEnabled)
            //{
            //    builder.GenerateId("form_"+Guid.NewGuid().ToString().Substring(0,5));
            //}
            ajaxHelper.ViewContext.Writer.Write(builder.ToString(TagRenderMode.StartTag));
            MvcForm form = new MvcForm(ajaxHelper.ViewContext);
            if (ajaxHelper.ViewContext.ClientValidationEnabled)
            {
                ajaxHelper.ViewContext.FormContext.FormId = builder.Attributes["id"];
            }
            ajaxHelper.RegisterStartupScript(GenernatejQueryFormCoreScripts(builder.Attributes["id"], options));
            return form;
        }

        private static string GenernatejQueryFormCoreScripts(string formID, jQueryAjaxOptions options)
        {
            StringBuilder scripts = new StringBuilder();
            scripts.Append("$(\"#" + formID + "\")")
                      .Append(".submit(function(event){ ")
                      .Append("if (!event.isDefaultPrevented()) {")
                      .Append("$.ajax({")
                      .Append("type:\"")
                      .Append(options.HttpMethod)
                      .Append("\",")
                      .Append("url:\"" + options.Url + "\",")
                      .Append("data:$(this).serialize()");

            if (!string.IsNullOrEmpty(options.Confirm))
                options.OnBeforeSend = "if (!confirm(\"" + options.Confirm + "\")) return false;" + options.OnBeforeSend;

            string targetID = string.IsNullOrEmpty(options.UpdateTargetID) ? formID : options.UpdateTargetID;

            #region Loading and blocking
            if (!string.IsNullOrEmpty(options.LoadingElementID))
            {
                string loadingID = "$(\"#" + options.LoadingElementID + "\")";
                options.OnBeforeSend += targetID + ".html(\"\");" + targetID + ".append(" + loadingID + ").show();";
                options.OnComplete += "$(\"body\").append(" + loadingID + ");" + loadingID + ".hide();";
            }
            else
            {
                if (options.AutoBlocking)
                {
                    options.OnBeforeSend += "uiHelper.blockUI($(\"#";
                    options.OnSuccess += "uiHelper.unblockUI($(\"#";
                    if (!string.IsNullOrEmpty(targetID))
                    {
                        options.OnBeforeSend += targetID;// "\"" + options.UpdateTargetID + "\"";
                        options.OnSuccess += targetID;// "\"" + options.UpdateTargetID + "\"";
                    }
                    options.OnBeforeSend += "\"));";
                    options.OnSuccess += "\"));";
                }
            }
            #endregion

            if (!string.IsNullOrEmpty(options.OnBeforeSend))
                scripts.Append(",beforeSend:function(XMLHttpRequest){")
                          .Append(options.OnBeforeSend)
                          .Append("}");

            if (!string.IsNullOrEmpty(options.OnComplete))
                scripts.Append(",complete:function(XMLHttpRequest,textStatus){")
                          .Append(options.OnComplete)
                          .Append("}");

            // if (!string.IsNullOrEmpty(options.UpdateTargetID))
            //{
            // targetID = "$(\"#" + options.UpdateTargetID + "\")";
            var _targetID = "$(\"#" + targetID + "\")";
            switch (options.InsertionMode)
            {
                case System.Web.Mvc.Ajax.InsertionMode.InsertAfter:
                    options.OnSuccess = _targetID + ".append(data);" + options.OnSuccess;
                    break;
                case System.Web.Mvc.Ajax.InsertionMode.InsertBefore:
                    options.OnSuccess = _targetID + ".prepend(data);" + options.OnSuccess;
                    break;
                case System.Web.Mvc.Ajax.InsertionMode.Replace:
                    options.OnSuccess = "if ($.browser.msie) " + _targetID + ".replaceWith('');" + _targetID + ".replaceWith(data);" + options.OnSuccess;
                    break;
            }
            //}

            if (!string.IsNullOrEmpty(options.OnSuccess))
            {
                scripts.Append(",success:function(data,textStatus){")
                          .Append(options.OnSuccess)
                          .Append("}");
            }

            if (string.IsNullOrEmpty(options.OnError))
                if (options.AutoHandlingError)
                    options.OnError = "portal.error(XMLHttpRequest, textStatus, errorThrown);";

            if (!string.IsNullOrEmpty(options.OnError))
                scripts.Append(",error:function(XMLHttpRequest,textStatus,errorThrown){")
                          .Append(options.OnError)
                          .Append("}");



            scripts.Append(" });")
                      .Append("}")
                      .Append("return false;")
                      .Append("});");

            return scripts.ToString();
        }
    }
}
